package com.aizhixin.lab.task.service;

import com.aizhixin.lab.jsrun.domian.CodeDomain;
import com.aizhixin.lab.jsrun.service.JsRunService;
import com.aizhixin.lab.jsrun.util.UnusualCode;
import com.aizhixin.lab.task.core.TaskInforCode;
import com.aizhixin.lab.task.domain.*;
import com.aizhixin.lab.task.entity.*;
import com.aizhixin.lab.task.repository.*;
import lombok.extern.slf4j.Slf4j;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.aizhixin.lab.account.dto.AccountDTO;
import com.aizhixin.lab.account.service.AccountService;
import com.aizhixin.lab.common.core.ApiReturnConstants;
import com.aizhixin.lab.common.core.DataValidity;
import com.aizhixin.lab.common.core.LabReportCore;
import com.aizhixin.lab.common.core.UserInforCore;
import com.aizhixin.lab.common.dto.SortDTO;
import com.aizhixin.lab.common.utils.PageJdbcUtil;
import com.aizhixin.lab.company.domain.AccountDomain;
import com.aizhixin.lab.company.service.UserService;
import com.aizhixin.lab.course.classes.domain.LabReportDomain;
import com.aizhixin.lab.course.classes.entity.LabReport;

@Slf4j
@Service
@Transactional
public class TaskStuAnswerService {
    @Autowired
    private TaskStuAnswerRepository taskStuAnswerRepository;
    @Autowired
    private PageJdbcUtil pageJdbcUtil;
    @Autowired
    private TaskStuFileService taskStuFileService;
    @Autowired
    private TaskStuInforService taskStuInforService;
    @Autowired
    private ReleaseTaskQuestionsService releaseTaskQuestionsService;
    @Autowired
    private ReleaseTaskService releaseTaskService;
    @Autowired
    private UserService userService;
    @Autowired
    private TaskStuCodeRepository taskStuCodeRepository;
    @Autowired
    private TaskStuStatisticsRepository taskStuStatisticsRepository;
    @Autowired
    private JsRunService jsRunService;

    public final static Map<String, String> scoreGrupp = new LinkedHashMap() {{
        put("90", "A+");
        put("85", "A");
        put("80", "B+");
        put("75", "B");
        put("70", "C+");
        put("65C", "65");
        put("65", "D+");
        put("55", "D");
        put("40", "F+");
        put("10", "F");
    }};

    public void save(TaskStuAnswer stuAnswer) {
        taskStuAnswerRepository.save(stuAnswer);
    }

    public void saveList(List<TaskStuAnswer> stuAnswers) {
        taskStuAnswerRepository.save(stuAnswers);
    }

    public List<TaskStuAnswer> findAllByTaskStuInforIdAndReleaseTaskId(String taskStuInforId, String releaseTaskId) {
        return taskStuAnswerRepository.findAllByTaskStuInforIdAndReleaseTaskIdAndDeleteFlag(taskStuInforId, releaseTaskId, DataValidity.VALID.getState());
    }

    public Map<String, Object> examineStuAnswer(ExamineStuAnswerDomain domain) {
        Map<String, Object> result = new HashMap<String, Object>();
        TaskStuAnswer taskStuAnswer = taskStuAnswerRepository.findByReleaseQuestionIdAndTaskStuInforId(domain.getReleaseQuestionId(), domain.getStuInfor());
        if (taskStuAnswer == null) {
            result.put(ApiReturnConstants.SUCCESS, Boolean.FALSE);
            result.put(ApiReturnConstants.ERROR, "该题学生未作答(默认0分)不进行评分");
            return result;
        }
        taskStuAnswer.setComment(getGrade(domain.getComment()) + "");
        taskStuAnswerRepository.save(taskStuAnswer);
        result.put(ApiReturnConstants.SUCCESS, Boolean.TRUE);
        result.put(ApiReturnConstants.DATA, taskStuAnswer.getComment());
        return result;
    }
    public Map<String, Object> examineModuleGrade(ExamineModuleGradeDomain domain) {
        Map<String, Object> result = new HashMap<String, Object>();
        domain.setComment(getGrade(domain.getComment()) + "");
        String sql="UPDATE t_task_stu_answer t LEFT JOIN t_release_task_question r ON t.release_question_id=r.ID SET t.`comment`='"+domain.getComment()+"' WHERE t.task_stu_infor_id='"+domain.getStuInfor()+"' AND r.question_type="+domain.getQuestionType();
        pageJdbcUtil.update(sql);
        result.put(ApiReturnConstants.SUCCESS, Boolean.TRUE);
        result.put(ApiReturnConstants.DATA, domain.getComment());
        return result;
    }
    private Integer getGrade(String type) {
        switch (type) {
            case "A+":
                return avgGrade(90, 100);
            case "A":
                return avgGrade(85, 89);
            case "B+":
                return avgGrade(80, 84);
            case "B":
                return avgGrade(75, 79);
            case "C+":
                return avgGrade(70, 74);
            case "C":
                return avgGrade(65, 69);
            case "D+":
                return avgGrade(60, 64);
            case "D":
                return avgGrade(50, 59);
            case "F+":
                return avgGrade(40, 49);
            case "F":
                return avgGrade(1, 39);
            default:
                return Integer.parseInt(type);
        }


    }

    private Integer avgGrade(Integer min, Integer max) {
        Random random = new Random();
        int i = random.nextInt(max);
        if (i < min) {
            return avgGrade(min, max);
        } else {
            return i;
        }
    }

    public void deleteByTaskStuInforId(String taskStuInforId) {
        taskStuAnswerRepository.deleteByTaskStuInforIdAndDeleteFlag(taskStuInforId, DataValidity.VALID.getState());
    }

    public List<TaskStuAnswer> findByIdIn(List<String> ids) {
        return taskStuAnswerRepository.findByIdInAndDeleteFlag(ids, DataValidity.VALID.getState());
    }

    /**
     * 随机指定范围内N个不重复的数
     * 最简单最基本的方法
     *
     * @param min 指定范围最小值
     * @param max 指定范围最大值
     * @param
     */
    private static int[] randomCommon(int min, int max, int n) {
        if (n > (max - min + 1) || max < min) {
            return null;
        }
        int[] result = new int[n];
        int count = 0;
        while (count < n) {
            int num = (int) (Math.random() * (max - min)) + min;
            boolean flag = true;
            for (int j = 0; j < n; j++) {
                if (num == result[j]) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                result[count] = num;
                count++;
            }
        }
        return result;
    }

    private static int getMyInt(int a, int b) {
        return (((double) a / (double) b) > (a / b) ? a / b + 1 : a / b);
    }

    public Map<String,Object> saveStuAnswer(AccountDTO account, StuAnswerSaveDomain domain) {
        Map<String,Object> result=new HashMap<>();
        String taskStuInforId = domain.getTaskStuId();
        List<StuAnswerParamsDomain> answerList = domain.getAnswerList();
        List<TaskStuAnswer> stuAnswers = new ArrayList<>();
        List<TaskStuFile> accessorys = new ArrayList<>();
        List<TaskStuCode> taskStuCodeList = new ArrayList<>();
        List<String> ids = new ArrayList<>();
        deleteByTaskStuInforId(taskStuInforId);
        //编程题处理，每次每次提交的编程题都会存储
        for (StuAnswerParamsDomain aitem : answerList) {
            ReleaseTaskQuestion releaseTaskQuestion = releaseTaskQuestionsService.findReleaseTaskQuestion(aitem.getReleaseQuestionId());

            if (aitem.getQuestionType() != null && 60 == aitem.getQuestionType()) {
                if (aitem.getStuAnswerAccessorylist()!=null&&aitem.getStuAnswerAccessorylist().size()>0){
                    continue;
                }
                TaskStuCode taskStuCode = new TaskStuCode();
                taskStuCode.setId(UUID.randomUUID().toString());
                taskStuCode.setReleaseQuestionId(aitem.getReleaseQuestionId());
                taskStuCode.setCodeRowNum(Integer.parseInt(aitem.getCodeRowNum()));
                taskStuCode.setSubmitCode(aitem.getRunCode());
                taskStuCode.setSubmitTime(new Date());
                taskStuCode.setLanguage(aitem.getLanguage());
                taskStuCode.setStuId(account.getId().toString());
                if (domain.isCommit()) {
                    taskStuCode.setTaskStatus(TaskInforCode.TASK_STATUS_UNCOMMIT);
                    CodeDomain codeDomain = new CodeDomain();
                    codeDomain.setCode(aitem.getRunCode());
                    codeDomain.setLang(aitem.getLanguage());
                    Map<String, String> resMap = jsRunService.codeRunDetection(codeDomain);
                    if (!resMap.isEmpty()) {
                        Random random = new Random();
                        TaskStuStatistics taskStuStatistics = new TaskStuStatistics();
                        taskStuStatistics.setId(UUID.randomUUID().toString());
                        taskStuStatistics.setCodeAdvise(resMap.get("verif"));
                        taskStuStatistics.setRunResult(resMap.get("runResult"));
                        Integer space = Integer.parseInt(aitem.getCodeRowNum()) / 1024 * 1000;
                        taskStuStatistics.setOccupySpace(space == 0 ? random.nextInt(50) + 1 : space);
                        taskStuStatistics.setExecuteTime(resMap.get("executeTime"));
                        taskStuStatistics.setReleaseQuestionId(aitem.getReleaseQuestionId());
                        taskStuStatistics.setStuId(account.getId().toString());
                        taskStuStatistics.setViolationNum(Integer.parseInt(String.valueOf(resMap.get("violationNum"))));
                        String[] codeNum = releaseTaskQuestion.getReferenceCode().split("\n");
                        Integer num = Integer.parseInt(aitem.getCodeRowNum()) - codeNum.length;

                        if (releaseTaskQuestion.getAnswer().equals(taskStuStatistics.getRunResult())) {
                            Integer score = randomCommon(95, 99, 1)[0];
                            taskStuStatistics.setScore(randomCommon(95, 99, 1)[0]);
                            if (num < 0) {
                                taskStuStatistics.setScore(score + num * 10 < 0 ? 10 : score + num * 10);
                            }
                        } else if (num >= 0) {
                            taskStuStatistics.setScore(randomCommon(60, 79, 1)[0]);
                        } else if (num < 0) {
                            Integer score = randomCommon(20, 59, 1)[0];
                            taskStuStatistics.setScore(score + num * 10 < 0 ? 10 : score + num * 10);
                        }
                        taskStuCode.setScore(taskStuStatistics.getScore());
                        taskStuCode.setRunResult(taskStuStatistics.getRunResult());
                        taskStuCode.setIsError(taskStuStatistics.getViolationNum());

                        TaskStuAnswer answer = new TaskStuAnswer();
                        String answerId = UUID.randomUUID().toString();
                        answer.setId(answerId);
                        answer.setStuAnswer(aitem.getRunCode());
                        answer.setComment(taskStuStatistics.getScore() + "");
                        answer.setTaskStuInforId(taskStuInforId);
                        answer.setStuId(account.getId());
                        answer.setStuName(account.getName());
                        answer.setReleaseQuestionId(aitem.getReleaseQuestionId());
                        answer.setDeleteFlag(DataValidity.VALID.getState());
                        answer.setRunCode(aitem.getRunCode());
                        answer.setRunResult(aitem.getRunResult());
                        answer.setReleaseTaskId(domain.getReleaseTaskId());
                        answer.setLanguage(aitem.getLanguage());
                        stuAnswers.add(answer);

                        taskStuStatisticsRepository.deleteByReleaseQuestionIdAndStuId(taskStuStatistics.getReleaseQuestionId(), taskStuStatistics.getStuId());
                        taskStuStatisticsRepository.save(taskStuStatistics);
                    }
                } else {
                    Integer score = 0;
                    CodeDomain codeDomain = new CodeDomain();
                    codeDomain.setCode(aitem.getRunCode());
                    codeDomain.setLang(aitem.getLanguage());
                    Map<String, String> resMap = jsRunService.codeRunDetection(codeDomain);
                    String[] codeNum = releaseTaskQuestion.getReferenceCode().split("\n");
                    Integer num = Integer.parseInt(aitem.getCodeRowNum()) - codeNum.length;
                    if (releaseTaskQuestion.getAnswer().equals(resMap.get("runResult"))) {
                        score = +randomCommon(95, 99, 1)[0];
                        if (num < 0) {
                            score = +score + num * 10 < 0 ? 10 : score + num * 10;
                        }
                    } else if (num >= 0) {
                        score = +randomCommon(60, 79, 1)[0];
                    } else if (num < 0) {
                        score = +randomCommon(20, 59, 1)[0];
                        score = +score + num * 10 < 0 ? 10 : score + num * 10;
                    }

                    taskStuCode.setScore(score);
                    taskStuCode.setRunResult(resMap.get("runResult"));
                    taskStuCode.setIsError(Integer.parseInt(String.valueOf(resMap.get("violationNum"))));

                    TaskStuAnswer answer = new TaskStuAnswer();
                    String answerId = UUID.randomUUID().toString();
                    answer.setId(answerId);
                    answer.setStuAnswer(aitem.getRunCode());
                    answer.setTaskStuInforId(taskStuInforId);
                    answer.setStuId(account.getId());
                    answer.setStuName(account.getName());
                    answer.setReleaseQuestionId(aitem.getReleaseQuestionId());
                    answer.setDeleteFlag(DataValidity.VALID.getState());
                    answer.setReleaseTaskId(domain.getReleaseTaskId());
                    answer.setLanguage(aitem.getLanguage());

                    stuAnswers.add(answer);
                    taskStuCode.setTaskStatus(TaskInforCode.TASK_STATUS_PENDING);
                }
                taskStuCodeList.add(taskStuCode);
            }
            String answerId = UUID.randomUUID().toString();
            //简答题关键字匹配
            if (aitem.getQuestionType() != null && 70 == aitem.getQuestionType()) {
                TaskStuAnswer taskStuAnswer = new TaskStuAnswer();
                int stuScore = 0;
                if (releaseTaskQuestion.getKeyword() != null) {
                    String[] keyWord = releaseTaskQuestion.getKeyword().split(",");
                    for (String str : keyWord) {
                        int score = 90;
                        if (keyWord.length >= 0) {
                            score = getMyInt(score, keyWord.length);
                        }
                        if (aitem.getStuAnswer() == null) {
                            continue;
                        }
                        if (aitem.getStuAnswer().contains(str)) {
                            stuScore += score;
                        }

                    }
                }
                taskStuAnswer.setId(answerId);
                taskStuAnswer.setComment(stuScore + "");
                taskStuAnswer.setReleaseQuestionId(aitem.getReleaseQuestionId());
                taskStuAnswer.setReleaseTaskId(domain.getReleaseTaskId());
                taskStuAnswer.setTaskStuInforId(aitem.getTaskStuId());
                taskStuAnswer.setCreatedDate(new Date());
                taskStuAnswer.setDeleteFlag(DataValidity.VALID.getState());
                taskStuAnswer.setStuAnswer(aitem.getStuAnswer());
                taskStuAnswer.setStuId(account.getId());
                taskStuAnswer.setStuName(account.getUserName());
                stuAnswers.add(taskStuAnswer);
            } else if (aitem.getQuestionType() != null && 70 != aitem.getQuestionType() && 60 != aitem.getQuestionType()) {
                ids.add(answerId);
                TaskStuAnswer answer = new TaskStuAnswer();
                answer.setId(answerId);
                answer.setTaskStuInforId(taskStuInforId);
                answer.setStuId(account.getId());
                answer.setStuName(account.getName());
                answer.setReleaseQuestionId(aitem.getReleaseQuestionId());
                answer.setStuAnswer(aitem.getStuAnswer());
                answer.setDeleteFlag(DataValidity.VALID.getState());
                answer.setRunCode(aitem.getRunCode());
                answer.setRunResult(aitem.getRunResult());
                answer.setReleaseTaskId(domain.getReleaseTaskId());
                answer.setLanguage(aitem.getLanguage());
                stuAnswers.add(answer);
            }
            if (aitem.getStuAnswerAccessorylist() != null && aitem.getStuAnswerAccessorylist().size() > 0) {
                for (StuAccessoryParamsDomain saitem : aitem.getStuAnswerAccessorylist()) {
                    TaskStuFile accessory = new TaskStuFile();
                    accessory.setId(UUID.randomUUID().toString());
                    accessory.setReleaseTaskId(domain.getReleaseTaskId());
                    accessory.setReleaseQuestionId(aitem.getReleaseQuestionId());
                    accessory.setStuAnswerId(answerId);
                    accessory.setStuId(account.getId());
                    accessory.setFileName(saitem.getFileName());
                    accessory.setFileUrl(saitem.getFileUrl());
                    accessory.setFileKey(saitem.getFileKey());
                    accessorys.add(accessory);
                }
            }
        }
        taskStuFileService.deleteByReleaseTaskIdAndStuId(domain.getReleaseTaskId(),account.getId());
        if (!accessorys.isEmpty()) {
//            taskStuFileService.deleteByReleaseTaskIdAndStuId(domain.getReleaseTaskId(),account.getId());
            taskStuFileService.saveList(accessorys);
        }
        if (!taskStuCodeList.isEmpty()) {
            taskStuCodeRepository.save(taskStuCodeList);
        }
        if (!stuAnswers.isEmpty()) {
            saveList(stuAnswers);
            if (domain.isCommit()) {
//                if (stuAnswers.size()<releaseTaskQuestionsService.findQuestionNum(domain.getReleaseTaskId())){
//                    result.put(ApiReturnConstants.SUCCESS,false);
//                    result.put(ApiReturnConstants.ERROR,"你有试题答案为空,无法提交试题,请检查!");
//                    return result;
//                }
                ReleaseTask releaseTask = releaseTaskService.findById(domain.getReleaseTaskId());
                TaskStuInfor byId = taskStuInforService.findById(taskStuInforId);

//				releaseTask.setPendingNum(releaseTask.getPendingNum()+1);
                if (byId.getTaskStatus().equals(TaskInforCode.TASK_STATUS_UNCOMMIT)) {
                    releaseTask.setCommitNum(releaseTask.getCommitNum() + 1);
                }
                releaseTaskService.save(releaseTask);
                byId.setTaskStatus(TaskInforCode.TASK_STATUS_PENDING);
                byId.setCommitTime(new Date());
                taskStuInforService.save(byId);
//                new Thread(new PaperRunable(domain,ids,taskStuInforService,releaseTaskQuestionsService,releaseTaskService,userService)).start();
            }
        }
        result.put(ApiReturnConstants.SUCCESS,true);
        result.put(ApiReturnConstants.CODE,"保存成功");
        return result;
    }

    public TaskStuAnswer findTaskAnswer(String releaseQuestionId, String taskStuInforId) {
        return taskStuAnswerRepository.findByReleaseQuestionIdAndTaskStuInforId(releaseQuestionId, taskStuInforId);
    }

    //统计正确率
    public Integer findTaskAccuracy(String releaseTaskId, Long stuId) {
        Integer total = taskStuAnswerRepository.countByReleaseTaskIdAndStuId(releaseTaskId, stuId);
        Integer correct = taskStuAnswerRepository.countByReleaseTaskIdAndStuIdAndIsCorrect(releaseTaskId, stuId, 1) * 100;
        return correct / total;
    }

    //批阅学生答案
    public TaskStuAnswer judgeStudentAnswer(String taskStuAnswerId, Integer isCorrect) {
        TaskStuAnswer taskStuAnswer = taskStuAnswerRepository.findByIdAndDeleteFlag(taskStuAnswerId, DataValidity.VALID.getState());
        taskStuAnswer.setIsCorrect(isCorrect);
        TaskStuAnswer save = taskStuAnswerRepository.save(taskStuAnswer);
        return save;
    }

    public Integer getAnswerNum(String taskStuInforId) {
        List<String> list = new ArrayList<>();
        list.add("");
        list.add(" class Main {\n" +
                "public static void main(String[] args) {\n" +
                "}\n" +
                "}");
        list.add("#include <stdio.h>\n" +
                "int main () {\n" +
                "return 0;\n" +
                "}");
        return taskStuAnswerRepository.countByTaskStuInforIdAndDeleteFlagAndStuAnswerNotIn(taskStuInforId, DataValidity.VALID.getState(), list);
    }

    RowMapper<QuestionTypeAvgDomain> avgDomainRowMapper = new RowMapper<QuestionTypeAvgDomain>() {

        @Override
        public QuestionTypeAvgDomain mapRow(ResultSet rs, int rowNum) throws SQLException {
            // TODO Auto-generated method stub
            QuestionTypeAvgDomain domain = new QuestionTypeAvgDomain();
            domain.setType(rs.getInt(1));
            domain.setGrade(rs.getDouble(2));
            return domain;
        }
    };

    public Map<String, Object> getAvg(String stuInfo) {
        Map map = new HashMap();
        String sql = "SELECT r.question_type type,AVG(t.`comment`) avg_grade FROM t_task_stu_answer t RIGHT JOIN t_release_task_question r ON t.release_question_id=r.ID WHERE t.task_stu_infor_id='" + stuInfo + "' GROUP BY r.question_type;";
        List<QuestionTypeAvgDomain> info = pageJdbcUtil.getInfo(sql, avgDomainRowMapper);
        info.forEach(item -> {
            map.put(item.getType(), item.getGrade()==null?0:item.getGrade());
        });
        return map;
    }

    public Map<String, Object> getStuTaskAvg(String stuInfo) {
        Map<String, Object> map = new HashMap();
        String sql = "SELECT AVG(t.`comment`) avg_grade FROM t_task_stu_answer t WHERE t.task_stu_infor_id='"+stuInfo+"'";
        Double avg = pageJdbcUtil.getDouble(sql);
        map.put("avg",avg==null?0:avg);
        return map;
    }
}
